﻿using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using Utility;

namespace Utility
{
    public static class CommonHelper
    {
        public static object GetKeyField<T>()
        {
            Type objTye = typeof(T);
            string _KeyField = "";
            PrimaryKeyAttribute KeyField;
            var name = objTye.Name;
            foreach (Attribute attr in objTye.GetCustomAttributes(true))
            {
                KeyField = attr as PrimaryKeyAttribute;
                if (KeyField != null)
                    _KeyField = KeyField.Name;
            }
            return _KeyField;
        }
        public static object GetTableField<T>()
        {
            Type objTye = typeof(T);
            string _KeyField = "";
            TableAttribute KeyField;
            var name = objTye.Name;
            foreach (Attribute attr in objTye.GetCustomAttributes(true))
            {
                KeyField = attr as TableAttribute;
                if (KeyField != null)
                    _KeyField = KeyField.Name;
            }
            return _KeyField;
        }
        //public static object GerRedisField<T>()
        //{
        //    Type objTye = typeof(T);
        //    string _KeyField = "";
        //    RedisKeyAttribute KeyField;
        //    var name = objTye.Name;
        //    foreach (Attribute attr in objTye.GetCustomAttributes(true))
        //    {
        //        KeyField = attr as RedisKeyAttribute;
        //        if (KeyField != null)
        //            _KeyField = KeyField.Name;
        //    }
        //    return _KeyField;
        //}
        public static bool IsEmpty(this object value)
        {
            if (value != null && !string.IsNullOrEmpty(value.ToString()))
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        public static string ToJson(this object obj)
        {
            var timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
            return JsonConvert.SerializeObject(obj, timeConverter);
        }
        public static T ToObject<T>(this string Json)
        {
            return Json == null ? default(T) : JsonConvert.DeserializeObject<T>(Json);
        }
        public static List<T> ToList<T>(this string Json)
        {
            return Json == null ? null : JsonConvert.DeserializeObject<List<T>>(Json);
        }
        /// <summary>
        /// 字串反序列化成linq对象
        /// </summary>
        /// <param name="Json">字串</param>
        /// <returns></returns>
        public static JObject ToJObject(this string Json)
        {
            return (Json == null || Json == "") ? JObject.Parse("{}") : JObject.Parse(Json.Replace("&nbsp;", ""));
        }

        public static string GetSize(long b)
        {
            return b.ToString() + "KB";
            if (b.ToString().Length <= 10)
                return GetMB(b);
            if (b.ToString().Length >= 11 && b.ToString().Length <= 12)
                return GetGB(b);
            if (b.ToString().Length >= 13)
                return GetTB(b);
            return String.Empty;
        }

        /// <summary>
        /// 将B转换为TB
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        private static string GetTB(long b)
        {
            for (int i = 0; i < 4; i++)
            {
                b /= 1024;
            }
            return b + "TB";
        }

        /// <summary>
        /// 将B转换为GB
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        private static string GetGB(long b)
        {
            for (int i = 0; i < 3; i++)
            {
                b /= 1024;
            }
            return b + "GB";
        }

        /// <summary>
        /// 将B转换为MB
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        private static string GetMB(long b)
        {
            for (int i = 0; i < 2; i++)
            {
                b /= 1024;
            }
            return b + "MB";
        }
        public static DataTable ToDataTable<T>(List<T> items)
        {
            var tb = new DataTable(typeof(T).Name);
            PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo prop in props)
            {
                Type t = GetCoreType(prop.PropertyType);
                tb.Columns.Add(prop.Name, t);
            }
            foreach (T item in items)
            {
                var values = new object[props.Length];
                for (int i = 0; i < props.Length; i++)
                {
                    values[i] = props[i].GetValue(item, null);
                }
                tb.Rows.Add(values);
            }
            return tb;
        }
        private static bool IsNullable(Type t)
        {
            return !t.IsValueType || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
        }
        private static Type GetCoreType(Type t)
        {
            if (t != null && IsNullable(t))
            {
                if (!t.IsValueType)
                {
                    return t;
                }
                else
                {
                    return Nullable.GetUnderlyingType(t);
                }
            }
            else
            {
                return t;
            }
        }
        public static List<TreeParentModel> BuildTreeStructure(DataTable dt, String FieldList)
        {
            List<TreeParentModel> TreeList = new List<TreeParentModel>();
            String[] arrGroup = FieldList.Split(',').OrderBy(p => p).ToArray();
            String[] arrField = arrGroup.Select(p => p.Split(':')[1]).ToArray();
            for (Int32 i = 0; i < arrField.Length; i++)
            {
                if (i == 0)
                {
                    var query = from t in dt.AsEnumerable()
                                group t by new { t1 = t.Field<String>(arrField[0]) } into m
                                select new
                                {
                                    id = arrField[0] + ":" + m.Key.t1,
                                    m.Key.t1,
                                    title = m.FirstOrDefault()[arrField[0] + "Name"],
                                    parentid = "0",
                                    count = m.Count()
                                };
                    query.ToList().ForEach(q =>
                    {
                        String title = q.title.ToString();
                        if (String.IsNullOrEmpty(q.t1))
                        {
                            title = "未定义";
                        }
                        TreeParentModel tree = new TreeParentModel() { id = q.id, parentid = q.parentid, spread = true, title = String.Format("{0}(<span class='treecount'>{1}</span>)", title, q.count), Count = q.count };
                        TreeList.Add(tree);

                    });
                }
                else if (arrField.Length > 1 && i == 1)
                {
                    var query = from t in dt.AsEnumerable()
                                group t by new { t1 = t.Field<String>(arrField[0]), t2 = t.Field<String>(arrField[1]) } into m
                                select new
                                {
                                    id = String.Format("{0}:{1}|{2}:{3}", arrField[0], m.Key.t1, arrField[1], m.Key.t2),
                                    m.Key.t1,
                                    m.Key.t2,
                                    title = m.FirstOrDefault()[arrField[1] + "Name"],
                                    parentid = String.Format("{0}:{1}", arrField[0], m.Key.t1),
                                    count = m.Count()
                                };
                    query.ToList().ForEach(q =>
                    {
                        String title = q.title.ToString();
                        if (String.IsNullOrEmpty(q.t2))
                        {
                            title = "未定义";
                        }
                        TreeParentModel tree = new TreeParentModel() { id = q.id, parentid = q.parentid, spread = true, title = String.Format("{0}(<span class='treecount'>{1}</span>)", title, q.count), Count = q.count };
                        TreeList.Add(tree);
                    });
                }
                else if (arrField.Length > 2 && i == 2)
                {
                    var query = from t in dt.AsEnumerable()
                                group t by new { t1 = t.Field<String>(arrField[0]), t2 = t.Field<String>(arrField[1]), t3 = t.Field<String>(arrField[2]) } into m
                                select new
                                {
                                    id = String.Format("{0}:{1}|{2}:{3}|{4}:{5}", arrField[0], m.Key.t1, arrField[1], m.Key.t2, arrField[2], m.Key.t3),
                                    m.Key.t1,
                                    m.Key.t2,
                                    m.Key.t3,
                                    title = m.FirstOrDefault()[arrField[2] + "Name"],
                                    parentid = String.Format("{0}:{1}|{2}:{3}", arrField[0], m.Key.t1, arrField[1], m.Key.t2),
                                    count = m.Count()
                                };
                    query.ToList().ForEach(q =>
                    {
                        String title = q.title.ToString();
                        if (String.IsNullOrEmpty(q.t3))
                        {
                            title = "未定义";
                        }
                        TreeParentModel tree = new TreeParentModel() { id = q.id, parentid = q.parentid, spread = true, title = String.Format("{0}(<span class='treecount'>{1}</span>)", title, q.count), Count = q.count };
                        TreeList.Add(tree);
                    });
                }
                else if (arrField.Length > 3 && i == 3)
                {
                    var query = from t in dt.AsEnumerable()
                                group t by new { t1 = t.Field<String>(arrField[0]), t2 = t.Field<String>(arrField[1]), t3 = t.Field<String>(arrField[2]), t4 = t.Field<String>(arrField[3]) } into m
                                select new
                                {
                                    id = String.Format("{0}:{1}|{2}:{3}|{4}:{5}|{6}:{7}", arrField[0], m.Key.t1, arrField[1], m.Key.t2, arrField[2], m.Key.t3, arrField[3], m.Key.t4),
                                    m.Key.t1,
                                    m.Key.t2,
                                    m.Key.t3,
                                    m.Key.t4,
                                    title = m.FirstOrDefault()[arrField[3] + "Name"],
                                    parentid = String.Format("{0}:{1}|{2}:{3}|{4}:{5}", arrField[0], m.Key.t1, arrField[1], m.Key.t2, arrField[2], m.Key.t3),
                                    count = m.Count()
                                };
                    query.ToList().ForEach(q =>
                    {
                        String title = q.title.ToString();
                        if (String.IsNullOrEmpty(q.t4))
                        {
                            title = "未定义";
                        }
                        TreeParentModel tree = new TreeParentModel() { id = q.id, parentid = q.parentid, spread = true, title = String.Format("{0}(<span class='treecount'>{1}</span>)", title, q.count), Count = q.count };
                        TreeList.Add(tree);
                    });
                }
                else if (arrField.Length > 4 && i == 4)
                {
                    var query = from t in dt.AsEnumerable()
                                group t by new { t1 = t.Field<String>(arrField[0]), t2 = t.Field<String>(arrField[1]), t3 = t.Field<String>(arrField[2]), t4 = t.Field<String>(arrField[3]), t5 = t.Field<String>(arrField[4]) } into m
                                select new
                                {
                                    id = String.Format("{0}:{1}|{2}:{3}|{4}:{5}|{6}:{7}|{8}:{9}", arrField[0], m.Key.t1, arrField[1], m.Key.t2, arrField[2], m.Key.t3, arrField[3], m.Key.t4, arrField[4], m.Key.t5),
                                    m.Key.t1,
                                    m.Key.t2,
                                    m.Key.t3,
                                    m.Key.t4,
                                    m.Key.t5,
                                    title = m.FirstOrDefault()[arrField[4] + "Name"],
                                    parentid = String.Format("{0}:{1}|{2}:{3}|{4}:{5}|{6}:{7}", arrField[0], m.Key.t1, arrField[1], m.Key.t2, arrField[2], m.Key.t3, arrField[3], m.Key.t4),
                                    count = m.Count()
                                };
                    query.ToList().ForEach(q =>
                    {
                        String title = q.title.ToString();
                        if (String.IsNullOrEmpty(q.t5))
                        {
                            title = "未定义";
                        }
                        TreeParentModel tree = new TreeParentModel() { id = q.id, parentid = q.parentid, spread = true, title = String.Format("{0}(<span class='treecount'>{1}</span>)", title, q.count), Count = q.count };
                        TreeList.Add(tree);
                    });
                }
                else if (arrField.Length > 5 && i == 5)
                {
                    var query = from t in dt.AsEnumerable()
                                group t by new { t1 = t.Field<String>(arrField[0]), t2 = t.Field<String>(arrField[1]), t3 = t.Field<String>(arrField[2]), t4 = t.Field<String>(arrField[3]), t5 = t.Field<String>(arrField[4]), t6 = t.Field<String>(arrField[5]) } into m
                                select new
                                {
                                    id = String.Format("{0}:{1}|{2}:{3}|{4}:{5}|{6}:{7}|{8}:{9}|{10}:{11}", arrField[0], m.Key.t1, arrField[1], m.Key.t2, arrField[2], m.Key.t3, arrField[3], m.Key.t4, arrField[4], m.Key.t5, arrField[5], m.Key.t6),
                                    m.Key.t1,
                                    m.Key.t2,
                                    m.Key.t3,
                                    m.Key.t4,
                                    m.Key.t5,
                                    m.Key.t6,
                                    title = m.FirstOrDefault()[arrField[5] + "Name"],
                                    parentid = String.Format("{0}:{1}|{2}:{3}|{4}:{5}|{6}:{7}|{8}:{9}", arrField[0], m.Key.t1, arrField[1], m.Key.t2, arrField[2], m.Key.t3, arrField[3], m.Key.t4, arrField[4], m.Key.t5),
                                    count = m.Count()
                                };
                    query.ToList().ForEach(q =>
                    {
                        String title = q.title.ToString();
                        if (String.IsNullOrEmpty(q.t6))
                        {
                            title = "未定义";
                        }
                        TreeParentModel tree = new TreeParentModel() { id = q.id, parentid = q.parentid, spread = true, title = String.Format("{0}(<span class='treecount'>{1}</span>)", title, q.count), Count = q.count };
                        TreeList.Add(tree);
                    });
                }
            }
            return TreeList;
        }
        public static bool IsExistFiile(string filePath)
        {
            return File.Exists(filePath);
        }
        public static T DeepCopy<T>(T obj)
        {
            //如果是字符串或值类型则直接返回
            if (obj is string || obj.GetType().IsValueType) return obj;

            object retval = Activator.CreateInstance(obj.GetType());
            FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
            foreach (FieldInfo field in fields)
            {
                try { field.SetValue(retval, DeepCopy(field.GetValue(obj))); }
                catch { }
            }
            return (T)retval;
        }
        //获取枚举描述
        public static string GetDescription<TEnum>(TEnum @enum)
        {
            FieldInfo fieldInfo = @enum.GetType().GetField(@enum.ToString());
            DescriptionAttribute[] descriptionAttributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
            return descriptionAttributes.Length > 0 ? descriptionAttributes[0].Description : @enum.ToString();
        }

        /// <summary>
        /// Model对比
        /// </summary>
        /// <typeparam Name="T"></typeparam>
        /// <param Name="oldModel"></param>
        /// <param Name="newModel"></param>
        public static List<string> CompareModel<T>(T oldModel, T newModel) where T : class
        {
            List<string> changeList = new List<string>();
            PropertyInfo[] properties = oldModel.GetType().GetProperties();
            foreach (System.Reflection.PropertyInfo item in properties)
            {
                TableContrastAttribute tableAttribute = item.GetCustomAttribute<TableContrastAttribute>();
                string name = item.Name;
                if (tableAttribute != null)
                    name = tableAttribute.FieldName;
                object oldValue = item.GetValue(oldModel);
                object newValue = item.GetValue(newModel);
                if (!oldValue.Equals(newValue))
                {
                    changeList.Add(name + " ：由[" + oldValue + "] 改为 [" + newValue + "]");
                }
            }
            return changeList;
        }
        /// <summary>
        /// RSA公钥加密
        /// </summary>
        /// <param name="xmlPublicKey">公钥</param>
        /// <param name="m_strEncryptString">加密内容</param>
        /// <returns></returns>
        public static string RSAEncrypt(string xmlPublicKey, string m_strEncryptString)
        {
            try
            {
                byte[] PlainTextBArray;
                byte[] CypherTextBArray;
                string Result;
                System.Security.Cryptography.RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(xmlPublicKey);
                PlainTextBArray = (new UTF8Encoding()).GetBytes(m_strEncryptString);
                CypherTextBArray = rsa.Encrypt(PlainTextBArray, false);
                Result = Convert.ToBase64String(CypherTextBArray);
                return Result;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
